package tau_sadna.tau_map;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.InetAddress;
import java.net.Socket;
import java.util.Date;

import android.util.Log;

public class Connection {

	public boolean isTerminated = false; 
	
	static String serverIP = "64.233.167.141";
	static int serverPort = 80;

	public boolean errState = false;

	Socket clientServerSocket;
	BufferedReader clientServerInput;
	PrintWriter clientServerOutput;

	public Connection() {
		try {
			Log.i("Connection", "Starting connection setup:");
			Log.i("Connection", "Getting host name by IP...");
			InetAddress serverAddr = InetAddress.getByName(serverIP);
			Log.i("Connection", "Server address is: " + serverAddr.toString());
			Log.i("Connection", "Opening socket...");
			clientServerSocket = new Socket(serverAddr, serverPort);
			Log.i("Connection", "Created server socket");
			Log.i("Connection", "Creating reader...");
			clientServerInput = new BufferedReader(new InputStreamReader(
					clientServerSocket.getInputStream()));
			Log.i("Connection", "Created reader");
			Log.i("Connection", "Creating writer...");
			clientServerOutput = new PrintWriter(
					new BufferedWriter(new OutputStreamWriter(
							clientServerSocket.getOutputStream())), true);
			Log.i("Connection", "Created writer");
			Log.i("Connection", "Connection setup complete.");
		} catch (Exception e) {
			errState = true;
			Log.e("Connection", "Failed to initiate link: " + e.getMessage());
		}
	}

	public void send(String message) {
		Log.i("Connection:send", "Printing message...");
		clientServerOutput.print(message);
		Log.i("Connection:send", "Printed message");
		Log.i("Connection:send", "Flushing printer...");
		clientServerOutput.flush();
		Log.i("Connection:send", "Flushed printer");
		Log.i("Connection:send", "Printing complete.");
	}

	public String ping() {
		send("GET / HTTP/1.1\r\nHost: tau-map.appspot.com\r\n\r\n");
		return recv();
	}
	
	public String getConfig() {
		send("GET /?name=config HTTP/1.1\r\nHost: tau-map.appspot.com\r\n\r\n");
		return recv();
	}
	
	public String getLayer(String layerName) {
		send("GET /?name="+layerName+" HTTP/1.1\r\nHost: tau-map.appspot.com\r\n\r\n");
		return recv();
	}

	public String recv() {
		//long startTime = new Date().getTime();
		String message = "";
		
		int parseState = 0;
		String blockSize = "";
		int nextBlockSize = 0;
		
		String data = "";
		
		char nextChar;
		
		while (true) {
			/*if (new Date().getTime() - startTime > maxConnTime) {
				return null;
			}*/
			if (isTerminated) {
				Log.v("Connection", "null2");
				return null;
			}
			try {
				if (!clientServerInput.ready()) {
					Thread.sleep(50);
					continue;
				}
			} catch (Exception e) {
				continue;
			}
			try {
				message += (char) clientServerInput.read();
			} catch (IOException e) {
				Log.v("Connection", "null1");
				return null;
			}
			
			
			//Log.v("Connection", "state: "+parseState+"\nmessage:\n"+message);
			
			switch (parseState) {
			case 0:
				if (message.length() >= 4) {
					if (message.endsWith("\r\n\r\n")) {
						parseState = 1;
						blockSize = "";
					}
				}
				break;
			case 1:
				blockSize += message.charAt(message.length()-1);
				parseState = 2;
				break;
			case 2:
				nextChar =  message.charAt(message.length()-1);
				if (nextChar != '\r') {
					blockSize += nextChar;
					break;
				}
				try {
					nextBlockSize = Integer.parseInt(blockSize, 16);
				} catch (Exception e) {
					Log.v("Connection", "null3. BlockSize: "+blockSize+" message: "+message);
					return null;
				}
				parseState = 3;
				break;
			case 3:
				parseState = 4;
				break;
			case 4:
				if (nextBlockSize == 0) {
					parseState = 8;
					break;
				}
				data += message.charAt(message.length()-1);
				parseState = 5;
				break;
			case 5:
				nextChar =  message.charAt(message.length()-1);
				if (nextChar != '\r') {
					data += nextChar;
					break;
				}
				parseState = 6;
				break;
			case 6:
				blockSize = "";
				parseState = 1;
				break;
			case 8:
				return data;
			}
		}
	}

	public void close() {
		try {
			Log.i("Connection:close", "Closing socket...");
			clientServerSocket.close();
			Log.i("Connection:close", "Closed socket");
		} catch (IOException e) {
			errState = true;
			Log.e("Connection:close",
					"Failed to close socket: " + e.getMessage());
		}
	}
}



//////////////////////////////////////////////////////





//////////////////////////////////////////////////////





